Jx.declare('Jx.platform.browser.dom.Document', {

	$extend: 'Jx.platform.browser.dom.Node',

	$requires: [ 'Jx.lib.Hash' ],

	$actions: [

		'createElement',

		'apply',

		'lookup'

	],

	elements: null,

	elementIdPrefix: 'jx-element-id',

	elementIdGen: 0,

	elementIdAttribute: 'data-element',

	elementClassNs: 'platform.browser.element',

	defaultElementClass: 'Jx.platform.browser.dom.Element',

	constructor: function(defaultView, dom){

		if (Jx.instanceOf(defaultView, 'Jx.platform.browser.dom.DefaultView')){
			
			this.defaultView = defaultView;

			this.$super(

				Array.prototype.slice.call(arguments, 1)
				
			);

		} else {

			throw Jx.createError('invalid defaultView instance: [', defaultView, ']');

		}

	},

	onInitialize: function(operation){

		this.elements = Jx.instantiate('Jx.lib.Hash');
		
		this.$super(arguments);

	},
	
	onApply: function(operation, node){

		var tagName = node.tagName.toLowerCase(),

			className = this.elementClassNs + '.' + tagName;

		operation.returnValue = Jx.instantiate(

			Jx.classExists( className ) ?

				className

				:

				this.defaultElementClass,

			[

				this,

				node,
				
				this.engine

			]

		);

	},

	onAfterApply: function(operation, node){

		var element = operation.returnValue,

			id = operation.id;

		if (!id){

			id = this.elementIdPrefix + ( ++this.elementIdGen );

			element.node.setAttribute( this.elementIdAttribute, id );

		}

		this.elements.set(id, element);

	},

	allowApply: function(operation, node){

		operation.returnValue = undefined;

		var result = this.$Dom.isDom(node, 1) && node.ownerDocument === this.node,

			elements = this.elements,

			id;

		if (result){

			id = this.getElementId(node);

			if ( elements.isSet( id ) ){

				operation.returnValue = elements.get(id);

			} else {

				operation.id = id;

			}

		}

		return result && !operation.returnValue;

	},

	allowLookup: function(operation, dom){

		var value = undefined,

			engine = this.engine,
			
			Dom = this.$Dom,

			type;

		//-- element by id
		if (Jx.isString(dom, true)){

			value = this.elements.get(dom);

		//-- dom nodes
		} else if (Dom.isDom(dom)){

			type = dom.nodeType;

			//-- document
			if (type == 9){

				value = node === this.node ?

					this

					:

					engine.createDocument(dom);

			//-- element
			} else if (type == 1){

				value = engine.createElement(dom);

			}

		//-- window
		} else if (Dom.isDom(value)){

			value = engine.createDefaultView(dom);

		}

		return value;

	},
	
	isValidNode: function(node){
		
		return this.$Dom.isDom(node, 9);
		
	},

	getElementId: function(dom){

		return this.$Dom.isDom(dom, 1) ?

			dom.getAttribute(this.elementIdAttribute)

			:

			undefined;

	}




});
